﻿using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace WgpgCore
{
    public sealed class RemoteFile : IDisposable
    {
        private String _file;
        private Boolean _isTemporary;

        public RemoteFile(String file)
        {
            _file = file;
            _isTemporary = false;
            LocalPath = null;

            String tmp = EnsureIsLocalFile(file, out _isTemporary);

            if (tmp == null || !File.Exists(tmp))
                throw new FileNotFoundException(file);

            LocalPath = tmp;
        }

        public String LocalPath { get; private set; }

        public void Dispose()
        {
            Clean();
        }

        ~RemoteFile()
        {
            Clean();
        }

        private void Clean()
        {
            try
            {
                if (_isTemporary && LocalPath != null)
                {
                    _isTemporary = false;
                    File.Delete(LocalPath);
                }

                _file = null;
                LocalPath = null;
            }
            catch
            {
                // Nothing todo
            }
        }

        private static String EnsureIsLocalFile(String file, out Boolean isTemporary)
        {
            isTemporary = false;

            if (String.IsNullOrEmpty(file))
                return null;

            Uri uri;
            try
            {
                uri = new Uri(file, UriKind.Absolute);
            }
            catch
            {
                return null;
            }

            if (uri.Scheme == Uri.UriSchemeFile)
                return file;

            if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
            {
                file = DownloadFile(file);

                if (file != null)
                    isTemporary = true;

                return file;
            }

            return null;
        }

        private static String DownloadFile(String uri)
        {
            if (String.IsNullOrEmpty(uri))
                return null;

            try
            {
                Byte[] bytes = MakeRequest(uri, "GET", null);
                String filename = Utils.GetTempFileName();
                File.WriteAllBytes(filename, bytes);

                return filename;
            }
            catch
            {
                return null;
            }
        }

        private static Byte[] MakeRequest(String uri, String method, IWebProxy proxy)
        {
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
            webRequest.AllowAutoRedirect = true;
            webRequest.Method = method;

            ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;

            if (proxy != null)
                webRequest.Proxy = proxy;

            try
            {
                using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
                {
                    using (Stream s = response.GetResponseStream())
                    {
                        return Utils.ReadFully(s, (Int32)response.ContentLength);
                    }
                }
            }
            catch
            {
                ServicePointManager.ServerCertificateValidationCallback -= ValidateRemoteCertificate;
                throw;
            }
        }

        /// <summary>
        /// Certificates are always valid, either there are not valid :)
        /// </summary>
        private static Boolean ValidateRemoteCertificate(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
        {
            return true;
        }
    }
}
